<script setup lang="ts">
import type { PositionItem } from "../apis/type"
import { computed, defineOptions, nextTick, onBeforeUnmount, onMounted, ref, watch } from "vue"

defineOptions({ name: "PositionList" })

const props = withDefaults(defineProps<{
  items: PositionItem[]
  loading: boolean
  total: number
  maxWidth?: number
  selectedId?: number | null
}>(), {
  items: () => [],
  selectedId: null
})

const emit = defineEmits<{
  (e: "select", item: PositionItem): void
  (e: "loadMore"): void
}>()

const paneStyle = computed(() => ({
  maxWidth: `${props.maxWidth ?? 240}px`
}))

const hasMore = computed(() => (props.items?.length || 0) < props.total)

const wrapRef = ref<HTMLElement | null>(null)
const sentinelRef = ref<HTMLElement | null>(null)
let io: IntersectionObserver | null = null
let observedEl: HTMLElement | null = null
let ioLock = false

async function tryLoadMore() {
  if (ioLock) return
  if (props.loading || !hasMore.value) return
  ioLock = true
  emit("loadMore")
  await nextTick()
  ioLock = false
}

function setupObserver() {
  teardownObserver()
  io = new IntersectionObserver(
    (entries) => {
      const entry = entries[0]
      if (entry?.isIntersecting) {
        tryLoadMore()
      }
    },
    {
      root: wrapRef.value ?? null,
      rootMargin: "300px 0px 0px 0px",
      threshold: 0
    }
  )
  refreshObserver()
}

function refreshObserver() {
  if (!io) return
  if (observedEl) {
    io.unobserve(observedEl)
    observedEl = null
  }
  if (sentinelRef.value && hasMore.value) {
    io.observe(sentinelRef.value)
    observedEl = sentinelRef.value
  }
}

function teardownObserver() {
  if (io) {
    if (observedEl) {
      io.unobserve(observedEl)
      observedEl = null
    }
    io.disconnect()
    io = null
  }
}

onMounted(() => {
  setupObserver()
})

watch(
  () => [(props.items?.length || 0), props.total, props.loading],
  () => nextTick(refreshObserver)
)

onBeforeUnmount(() => {
  teardownObserver()
})
</script>

<template>
  <div class="pane-left" ref="wrapRef" :style="paneStyle">
    <div class="list">
      <ElSkeleton v-if="loading && (!items || items.length === 0)" :rows="6" animated />

      <div
        v-for="item in items"
        :key="item.id"
        class="list-item"
        :class="{ selected: selectedId === item.id }"
        @click="emit('select', item)"
      >
        <div class="item-header">
          <div class="title">
            {{ item.positionName }}
          </div>
          <div class="salary" v-if="item.salary">
            {{ item.salary }}
          </div>
        </div>
        <div class="meta">
          <span class="company">{{ item.companyName }}</span>
          <span class="dot">·</span>
          <span class="city">{{ item.workCity }}</span>
        </div>
        <div class="position-info">
          <span v-if="item.workType" class="info-tag">{{ item.workType }}</span>
          <span v-if="item.period" class="info-tag">{{ item.period }}</span>
        </div>
        <div class="tags">
          <span v-for="t in item.tags" :key="t" class="tag">{{ t }}</span>
        </div>
      </div>

      <div ref="sentinelRef" class="sentinel" />

      <div class="list-footer">
        <span v-if="loading">加载中...</span>
        <span v-else-if="!hasMore">没有更多了</span>
      </div>
    </div>
  </div>
</template>

<style scoped lang="scss">
.pane-left {
  background: #fff;
  border: 1px solid #eef2f7;
  border-radius: 12px;
  padding: 12px;
  overflow: auto;
  max-height: calc(100vh - 180px);
  width: 100%;
}

.list {
  display: flex;
  flex-direction: column;
  gap: 12px;
}

.list-item {
  border: 1px solid #eef2f7;
  border-radius: 12px;
  padding: 12px;
  cursor: pointer;
  transition: all 0.2s ease-in-out;
  background-color: #fff;

  &:hover {
    border-color: #cdd6e1;
    box-shadow: 0 2px 10px rgba(16, 24, 40, 0.06);
    transform: translateY(-1px);
  }

  &.selected {
    border-color: #3b82f6;
    background-color: #f0f9ff;
    box-shadow: 0 2px 10px rgba(59, 130, 246, 0.15);

    .item-header {
      .title {
        color: #3b82f6; /* Change title color when selected */
        font-weight: 700; /* Make title bolder when selected */
      }

      .salary {
        color: #1e40af; /* Darker blue for salary when selected */
      }
    }
  }

  &.selected {
    border-color: #3b82f6;
    background-color: #f0f9ff;
    box-shadow: 0 2px 10px rgba(59, 130, 246, 0.15);
  }
}

.item-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  margin-bottom: 4px;
}

.title {
  font-size: 16px;
  font-weight: 600;
  color: #1f2d3d;
}

.salary {
  font-size: 14px;
  font-weight: 600;
  color: #ff6b6b;
}

.meta {
  color: #6b7280;
  font-size: 13px;
  display: flex;
  align-items: center;
  gap: 6px;
  margin-bottom: 8px;
}
.meta .dot {
  color: #9aa4b2;
}

.tags {
  display: flex;
  gap: 8px;
  flex-wrap: wrap;
}
.tag {
  background-color: #f3f6fb;
  color: #3b82f6;
  border: 1px solid #e5edf9;
  border-radius: 999px;
  padding: 2px 8px;
  font-size: 12px;
}

.position-info {
  display: flex;
  gap: 8px;
  margin-bottom: 6px;
  flex-wrap: wrap;
}

.info-tag {
  background-color: #f0f9ff;
  color: #38bdf8;
  border: 1px solid #e0f2fe;
  border-radius: 999px;
  padding: 2px 8px;
  font-size: 12px;
}

.sentinel {
  height: 1px;
}

.list-footer {
  text-align: center;
  color: #6b7280;
  padding: 8px 0 0;
}
</style>
